import uid2 from "uid2";
import os from "os";
import { format } from "date-fns";
import CryptoJS from "crypto-js";
import * as fs from "fs";
import { Log } from "./Log";
import net from "net";
import _ from "lodash";

/**
 * 工具类
 *
 * @export
 * @class Tools
 */
export class Tools {
    /**
     * 获取ipv4地址
     *
     * @static
     * @return {*}  {string}
     * @memberof Utils
     */
    public static getIPV4(): string {
        const infos = os.networkInterfaces();
        for (const key in infos) {

            const list = infos[key];
            for (const i of list) {
                if (i.family === "IPv4" && i.address !== "127.0.0.1") {
                    return i.address;
                }
            }
        }
    }


    /**
     * 验证邮箱
     *
     * @static
     * @param {string} email
     * @return {*}  {boolean}
     * @memberof Utils
     */
    public static verifyEmail(email: string): boolean {
        const reg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/;
        return reg.test(email);
    }

    /**
     * 验收手机号
     *
     * @static
     * @param {string} phone
     * @return {*}  {boolean}
     * @memberof Utils
     */
    public static verifyPhone(phone: string): boolean {
        const reg = /^1[3456789]\d{9}$/;
        return reg.test(phone);
    }


    /**
     * 验证密码
     *
     * @static
     * @param {string} password
     * @return {*}  {boolean}
     * @memberof Utils
     */
    public static verifyPassword(password: string): boolean {
        const reg = /^[a-zA-Z0-9]{6,16}$/;
        return reg.test(password);
    }

    // 对数组打乱顺序
    public static shuffle(arr: any[]) {
        for (let i = 0; i < arr.length; i++) {
            const randomIndex = Math.floor(Math.random() * arr.length);
            [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
        }
        return arr;
    }


    public static getCurrentTime(): string {

        return format(new Date(), "HH:mm:ss");
    }




    /**
     * 获取实例的类名
     *
     * @static
     * @param {*} obj
     * @return {*}  {string}
     * @memberof Utils
     */
    public static getClassName(obj: any): string {
        return obj.constructor.name;
    }



    /**
     * 唯一id
     *
     * @static
     * @return {*}  {string}
     * @memberof Utils
     */
    public static getUID(): string {

        return uid2(10);
    }


    /**服务器时间 */
    public static getServerTime() {

        return Math.floor(new Date().getTime() / 1000);
    }


    /**
     * 服务器时间毫秒级别
     *
     * @static
     * @return {*}  {number}
     * @memberof Tools
     */
    public static getServerTimeMS(): number {

        return Math.floor(new Date().getTime());
    }


    //**服务器日期 */
    public static getServerDate(): string {


        const today = new Date();
        const dateStr = today.getFullYear() + '-' + (today.getMonth() + 1) + '-'
            + today.getDate() + ' ' + today.getHours() + ':'
            + today.getMinutes() + ':' + today.getSeconds();
        return dateStr;
    }




    public static aes_decrypt(data: string, key: string): string {

        const bytes = CryptoJS.AES.decrypt(data, key);

        if (bytes) {
            return bytes.toString(CryptoJS.enc.Utf8);
        }
    }

    public static aes_encrypt(data: string, key: string): string {

        return CryptoJS.AES.encrypt(data, key).toString();
    }


    public static profileFuction(func: Function, tag: string): number {

        const startTime: number = Date.now();
        func();
        const endTime: number = Date.now();

        const cost: number = endTime - startTime;

        console.log(`[${tag}] profile cost time ${cost} ms`);

        return cost;
    }

    /**
     * 写文件
     *
     * @static
     * @param {string} filepath
     * @param {string} content
     * @memberof Tools
     */
    public static writeFile(filepath: string, content: string): Promise<boolean> {

        return new Promise((resolve, reject) => {
            fs.writeFile(filepath, content, (err: NodeJS.ErrnoException) => {

                if (err) {
                    Log.error(`write file failed ${err}`);
                    resolve(false);
                }
                else {
                    resolve(true);
                }

            });
        });

    }


    /**
     * 读取文件
     *
     * @static
     * @param {string} filepath
     * @return {*}  {Promise<string>}
     * @memberof Tools
     */
    public static readFile(filepath: string): Promise<string> {
        return new Promise((resolve, reject) => {
            fs.readFile(filepath, { encoding: "utf-8" }, (error: NodeJS.ErrnoException, data: string) => {
                if (error) {
                    resolve(null);
                }
                else {
                    resolve(data);
                }
            });
        });

    }

    public static isFileExsited(filepath: string): Promise<boolean> {

        return new Promise((resolve, reject) => {
            fs.access(filepath, fs.constants.F_OK, (error) => {
                if (error) {

                    resolve(false);
                }
                else {
                    resolve(true);
                }
            });
        });

    }


    // 定义一个函数，传入端口号作为参数
    public static checkPort(port: number): Promise<boolean> {

        return new Promise((resolve, reject) => {
            // 创建一个服务器实例
            let server = net.createServer();

            // 监听服务器的错误事件
            server.on('error', (err: any) => {
                if (err.code === 'EADDRINUSE') {
                    // 如果端口被占用，返回错误信息
                    resolve(false);
                }
                else {
                    resolve(false);
                }
            });

            // 监听服务器的监听事件
            server.on('listening', () => {
                // 如果端口可用，关闭服务器，并返回true
                server.close(() => { });
                resolve(true);
            });

            // 监听服务器的连接事件
            server.listen(port);
        });

    }


    /**
     * 获取没被占用的端口号
     *
     * @static
     * @param {number} startPort
     * @return {*}  {Promise<number>}
     * @memberof Tools
     */
    public static getRPCPort(startPort: number): Promise<number> {

        return new Promise(async (resolve, reject) => {
            if (await this.checkPort(startPort)) {
                resolve(startPort);

            }
            else {
                resolve(await this.getRPCPort(startPort + 1));
            }
        });
    }


    public static getRandomNumber(rates: { key: number, rate: number }[],): number {

        let totalRate: number = 0;
        _.each(rates, (e) => {
            totalRate += e.rate;
        })

        const randomRate: number = _.random(0, totalRate);

        let curRate:number = 0
        for (let index = 0; index < rates.length; index++) {
            const element: { key: number, rate: number } = rates[index];
            curRate += element.rate
            if (randomRate <= curRate) {
                return element.key;
            }

        }
    }
}






